package cn.mitool.crypto.symmetric;

import cn.mitool.core.util.StringUtil;
import cn.mitool.crypto.Mode;
import cn.mitool.crypto.Padding;
import org.apache.commons.lang3.ArrayUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Objects;

/**
 * DES
 *
 * @author dragon
 * @version 1.0
 * @date 2024/7/12 10:31
 */
public class DES {

    /**
     * 模式
     */
    private final String mode;

    /**
     * 补码方式
     */
    private final String padding;

    /**
     * 密钥
     */
    private final byte[] key;

    /**
     * 偏移向量
     */
    private final byte[] iv;


    public DES(Mode mode, Padding padding, String key) {
        this(mode, padding, key.getBytes(StandardCharsets.UTF_8), null);
    }

    public DES(Mode mode, Padding padding, String key, String iv) {
        this(mode, padding, key.getBytes(StandardCharsets.UTF_8), iv.getBytes(StandardCharsets.UTF_8));
    }

    public DES(Mode mode, Padding padding, byte[] key, byte[] iv) {
        this.mode = mode.name();
        this.padding = padding.name();
        this.key = key;
        this.iv = iv;
    }

    /**
     * 初始化向量（IV），它是一个随机生成的字节数组，用于增加加密和解密的安全性
     *
     * @return 初始化向量
     */
    public String generateIV() {
        SecureRandom random = new SecureRandom();
        // AES CBC模式需要16字节的初始化向量
        byte[] iv = new byte[16];
        random.nextBytes(iv);

        return new String(iv);
    }

    /**
     * 加密
     *
     * @param data 明文
     * @return 密文
     */
    public String encrypt(String data) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
        return encrypt(data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 加密
     *
     * @param data 明文
     * @return 密文
     */
    public String encrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // 创建AES加密器
        Cipher cipher = Cipher.getInstance(Objects.requireNonNull(StringUtil.format("DES/{}/{}", mode, padding)));

        SecretKeySpec keySpec = new SecretKeySpec(key, "DES");
        if (ArrayUtils.isEmpty(iv)) {
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        } else {
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        }

        // 加密字节数组
        byte[] ciphertext = cipher.doFinal(data);

        return Base64.getEncoder().encodeToString(ciphertext);
    }

    /**
     * 解密
     *
     * @param data 密文
     * @return 明文
     */
    public String decrypt(String data) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
        return decrypt(data.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 解密
     *
     * @param data 密文
     * @return 明文
     */
    public String decrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        // 创建AES加密器
        Cipher cipher = Cipher.getInstance(Objects.requireNonNull(StringUtil.format("DES/{}/{}", mode, padding)));

        SecretKeySpec keySpec = new SecretKeySpec(key, "DES");
        if (ArrayUtils.isEmpty(iv)) {
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
        } else {
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        }

        byte[] ciphertext = Base64.getDecoder().decode(data);

        // 解密字节数组
        byte[] plaintextBytes = cipher.doFinal(ciphertext);

        return new String(plaintextBytes, StandardCharsets.UTF_8);
    }

}
